package com.orange.framework.interceptor;

import cn.hutool.core.util.ObjectUtil;
import com.orange.common.base.entity.AppInfo;
import com.orange.common.base.redis.utils.RedisCache;
import com.orange.common.constant.HeaderConstants;
import com.orange.common.enums.CallSourceEnum;
import com.orange.common.enums.ResultCodeEnum;
import com.orange.common.exception.BusinessException;
import com.orange.common.utils.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * 请求头参数校验
 *
 * @Author YWF
 * @Date 2022/1/25 15:09
 */
public abstract class HeaderParamsCheckInterceptor implements HandlerInterceptor {

    @Value("${app.developer.cache_key}")
    private String appInfoCacheKey;

    @Value("${app.sign_param.enabled}")
    protected boolean signEnabled;

    private final static Logger logger = LoggerFactory.getLogger(HeaderParamsCheckInterceptor.class);

    protected final static long REQUEST_OUT_TIME = 5 * 60 * 1000;

    @Autowired
    protected RedisCache redisCache;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){
        String appKey = request.getHeader(HeaderConstants.X_APPKEY);
        String appVersion = request.getHeader(HeaderConstants.APP_VERSION);
        String timestamp = request.getHeader(HeaderConstants.X_TIMESTAMP);
        String nonce = request.getHeader(HeaderConstants.X_NONCE);
        String sign = request.getHeader(HeaderConstants.X_SIGN);
        // AppKey校验
        AppInfo appInfo = appKeyParamsCheck(appKey, appVersion);
        // 请求头参数校验
        if (signEnabled){
            this.headerParamsCheck(timestamp,nonce,sign);
        }
        // 签名校验
        return this.signValidateHandle(request, handler, appInfo, timestamp, nonce, sign);
    }

    protected abstract boolean signValidateHandle(HttpServletRequest request, Object handler, AppInfo appInfo, String timestamp, String nonce, String sign);

    private void headerParamsCheck(String timestamp,String nonce,String sign){
        /*校验请求头参数 timestamp,nonce,sign*/
        if (StringUtil.isAnyBlank(timestamp,nonce,sign)){
            throw new BusinessException(ResultCodeEnum.PARAM_NOT_COMPLETE);
        }
        /*检验时间戳类型*/
        try {
            Long.valueOf(timestamp);
        } catch (NumberFormatException e) {
            throw new BusinessException(ResultCodeEnum.REQUEST_TIME_INVALID);
        }
    }

    private AppInfo appKeyParamsCheck(String appKey, String appVersion) {
        if (StringUtil.isBlank(appKey)){
            throw new BusinessException(ResultCodeEnum.APPKEY_NOT_COMPLETE);
        }
        AppInfo appInfo = redisCache.hget(appInfoCacheKey, appKey);
        if (ObjectUtil.isEmpty(appInfo)){
            throw new BusinessException(ResultCodeEnum.APPKEY_IS_INVALID);
        }
        String callSource = appInfo.getAppType();
        /*请求来源必须合法*/
        if (!CallSourceEnum.isValid(callSource)){
            throw new BusinessException(ResultCodeEnum.REQUEST_SOURCE_INVALID);
        }
        /*请求来源校验：Android和ios必须要携带App版本号*/
        if ((CallSourceEnum.ANDROID.name().equals(callSource) || CallSourceEnum.IOS.name().equals(callSource)) && StringUtil.isEmpty(appVersion)){
            throw new BusinessException(ResultCodeEnum.APP_VERSION_IS_INVALID);
        }
        return appInfo;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }

}
